#!/bin/bash

export DAEMON_SERVICE_LOG_DIR=/var/log/zmicro/daemon

export DAEMON_PREFIX=zmicro_
export DEAMON_SUFFIX=.service

export DAEMON_SERVICE_DIR=/etc/systemd/system
export DAEMON_SERVICE_SCRIPT_DIR=${DAEMON_SERVICE_DIR}/zcorky

# export DAEMON_SERVICE_DIR_MAC_OS=/Library/LaunchDaemons
# export DAEMON_SERVICE_SCRIPT_DIR_MAC_OS=${DAEMON_SERVICE_DIR_MAC_OS}/com.zcorky.zmicro

# @TODO
if [ "$(os::is_macos)" = "true" ]; then
  export DAEMON_PREFIX=com.zcorky.zmicro.
  export DEAMON_SUFFIX=.plist

  export DAEMON_SERVICE_DIR=/Library/LaunchDaemons
  export DAEMON_SERVICE_SCRIPT_DIR=${DAEMON_SERVICE_DIR}/com.zcorky.zmicro
fi

if [ ! -d "$DAEMON_SERVICE_LOG_DIR" ]; then
  sudo mkdir -p $DAEMON_SERVICE_LOG_DIR
fi
if [ ! -w "$DAEMON_SERVICE_LOG_DIR" ]; then
  sudo chown -R $USER $DAEMON_SERVICE_LOG_DIR
fi
# create script dir
if [ ! -d $DAEMON_SERVICE_SCRIPT_DIR ]; then
  sudo mkdir $DAEMON_SERVICE_SCRIPT_DIR
fi

daemon_get_service_name() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    echo "com.zcorky.zmicro.${name}"
    return
  fi

  echo "zmicro_${name}"
}

daemon_parse_service_name() {
  local service_name=$1
  if [ "$service_name" = "" ]; then
    log::error "[daemon_parse_service_name] service_name is required"
    exit 1
  fi

  local remove_dot_service=$(string::remove $service_name $DEAMON_SUFFIX)
  local remove_prefix=$(string::remove $remove_dot_service $DAEMON_PREFIX)

  echo $remove_prefix
}

daemon_service::get_path() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(os::is_macos)" = "true" ]; then
    # echo "/System/Library/LaunchDaemons/${service}.plist"
    echo "${DAEMON_SERVICE_DIR}/${service}.plist"
    return
  fi

  echo "/etc/systemd/system/${service}.service"
}

daemon_get_service_log_path() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  # local service=$(daemon_get_service_name $name)
  echo "$DAEMON_SERVICE_LOG_DIR/$name.log"
}

daemon_is_service_exist() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "[daemon_is_service_exist] name is required"
    exit 1
  fi

  local service_path=$(daemon_service::get_path $name)
  if [ ! -f $service_path ]; then
    echo "false"
  else
    echo "true"
  fi
}

daemon_is_service() {
  # zmicro_vscode_protect.service
  local service_name=$1
  if [ "$service_name" = "" ]; then
    log::error "[daemon_is_service] service_name is required"
    exit 1
  fi

  echo "$(string::match $service_name ^${DAEMON_PREFIX})"
}

daemon_has_service() {
  daemon_is_service_exist $@
}

daemon_logs() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  while [[ $# -gt 0 ]]; do
    local key=$1
    local value=$2
    case $key in
    -f | --follow)
      os::set_var is_daemon_logs_follow true
      shift
      ;;
    *)
      if [ "$(string::match $key ^-)" = "true" ]; then
        log::error "[daemon_logs] unknown parameter \"$key\""
        exit 1
      fi

      shift
      ;;
    esac
  done

  if [ "$(os::is_macos)" = "true" ]; then
    # local log_path=/tmp/$service.log
    # local error_log_path=/tmp/$service.error.log
    local log_path=$(daemon_get_service_log_path $name)

    if [ "$is_daemon_logs_follow" = "true" ]; then
      tail -f $log_path
    else
      cat $log_path
    fi
    return
  fi

  if [ "$is_daemon_logs_follow" = "true" ]; then
    sudo journalctl -u $service -f
  else
    sudo journalctl -u $service -r
  fi
}

daemon_status() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    sudo launchctl list | grep $service
    return
  fi

  sudo systemctl status $service
}

daemon_start() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    local service_path=$(daemon_service::get_path $1)
    sudo launchctl list | grep $service >>/dev/null 2>&1
    if [ "$?" != "0" ]; then
      sudo launchctl load $service_path
    fi

    return
  fi

  sudo systemctl start $service
}

daemon_stop() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    local service_path=$(daemon_service::get_path $1)
    sudo launchctl list | grep $service >>/dev/null 2>&1
    if [ "$?" = "0" ]; then
      sudo launchctl unload $service_path
    fi
    return
  fi

  sudo systemctl stop $service
}

daemon_restart() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    daemon_stop $1
    daemon_start $1
    return
  fi

  sudo systemctl restart $service
}

daemon_reload() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    daemon_restart $1
    return
  fi

  sudo systemctl reload $service
}

daemon_enable() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    local service_path=$(daemon_service::get_path $1)
    sudo launchctl enable $service_path
    return
  fi

  sudo systemctl enable $service
}

daemon_disable() {
  local name=$1
  if [ "$name" = "" ]; then
    log::error "name is required"
    exit 1
  fi

  local service=$(daemon_get_service_name $1)
  if [ "$(daemon_is_service_exist $1)" = "false" ]; then
    log::error "daemon service($1) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    local service_path=$(daemon_service::get_path $1)
    sudo launchctl disable $service_path
    return
  fi

  sudo systemctl disable $service
}

daemon_create() {
  local name=$1
  local command=${@:2}

  if [ "$name" = "" ] || [ "$command" = "" ]; then
    log::error "daemon service and command are required"
    exit 1
  fi

  if [ "$(daemon_is_service_exist $name)" = "true" ]; then
    local service_path=$(daemon_service::get_path $name)
    log::error "found daemon service(${name}), please it manual: ${service_path}"
    exit 1
  fi

  local service_name=$(daemon_get_service_name $name)
  local service_path=$(daemon_service::get_path $name)
  local service_log_path=$(daemon_get_service_log_path $name)
  sudo touch $service_path

  local script_path=$DAEMON_SERVICE_SCRIPT_DIR/$name

  if [ "$(os::is_macos)" = "true" ]; then
    # create script
    sudo tee $script_path >>/dev/null <<EOF
#!/bin/bash
export PATH=/usr/local/lib/zmicro/bin:\$PATH

# @TODO
# override tput
#   => fix tput: No value for $TERM and no -T specified

tput() {
  return
}

export -f tput

${command}
EOF
    sudo chmod +x $script_path

    # create launchctl plist
    sudo tee $service_path >>/dev/null <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Disabled</key>
    <false/>
    <key>Label</key>
    <string>${service_name}</string>
    <key>KeepAlive</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
      <string>${script_path}</string>
    </array>
    <key>StandardErrorPath</key>
    <string>${service_log_path}</string>
    <key>StandardOutPath</key>
    <string>${service_log_path}</string>
    <key>UserName</key>
    <string>$(os::username)</string>
  </dict>
</plist>
EOF

    # start
    sudo launchctl load $service_path
    log::success "daemon serice ${name} created"
    return
  fi

  # Linux
  # create script
    sudo tee $script_path >>/dev/null <<EOF
#!/bin/bash
export PATH=/usr/local/lib/zmicro/bin:\$PATH

# @TODO
# override tput
#   => fix tput: No value for $TERM and no -T specified

tput() {
  return
}

export -f tput

${command}
EOF
    sudo chmod +x $script_path

  sudo tee $service_path >>/dev/null <<EOF
[Unit]
Description=zmicro service - ${name}

[Service]
# EnvironmentFile=$HOME/.bashrc
Environment=ZMICRO_HOME=${ZMICRO_HOME}
# Environment=ZMICRO_BIN_PATH=${ZMICRO_BIN_PATH}
Environment=PATH=/usr/local/bin:${ZMICRO_HOME}/bin:${PATH}
ExecStart=${script_path}
Restart=on-failure
Type=simple

[Install]
WantedBy=multi-user.target 
EOF

  sudo systemctl daemon-reload
  sudo systemctl start $service_name

  log::success "daemon serice ${name} created"
}

daemon_remove() {
  local name=$1

  if [ "$name" = "" ]; then
    log::error "daemon service and command are required"
    exit 1
  fi

  local service_name=$(daemon_get_service_name $name)
  local service_path=$(daemon_service::get_path $name)
  if [ "$(daemon_is_service_exist $name)" = "false" ]; then
    log::error "daemon service(${name}) not found"
    exit 1
  fi

  if [ "$(os::is_macos)" = "true" ]; then
    # 1. stop
    daemon_stop $name
    # 2. remove
    # @TODO
    sudo rm -f $service_path
    log::success "daemon serice ${name} removed"
    return
  fi

  sudo systemctl stop $service_name
  sudo rm -f $service_path
  sudo systemctl daemon-reload
  log::success "daemon serice ${name} removed"
}

daemon_list() {
  local service_files=$(array::filter daemon_is_service $(ls $DAEMON_SERVICE_DIR))

  parser() {
    local index=$1
    local file_name=$2
    local service_name=$(daemon_parse_service_name $file_name)
    echo $service_name
  }

  array::each parser $service_files
}

daemon_count() {
  local services=$(daemon_list $@)

  array::length $services
}

export -f daemon_get_service_name
export -f daemon_parse_service_name
export -f daemon_service::get_path
export -f daemon_get_service_log_path
export -f daemon_is_service_exist
export -f daemon_has_service
export -f daemon_is_service

export -f daemon_logs
export -f daemon_status
export -f daemon_start
export -f daemon_stop
export -f daemon_restart
export -f daemon_reload
export -f daemon_enable
export -f daemon_disable

export -f daemon_create
export -f daemon_remove

export -f daemon_list
export -f daemon_count
